package owg.util.data;

import java.util.WeakHashMap;

/**
 * This class can be used to assign a property to each instance of a given type, when it is not possible to explicitly declare new fields.
 * Notably, this serves as a hack to enable interfaces to have mutable fields. 
 * This class allows the field values to be garbage collected when the object instance is no longer available.
 * @param <I> The type of the object to which we want to assign a field.
 * @param <P> The type of the field. The field instance should be mutable, for instance: AtomicInteger or ArrayList is mutable, Integer or String is not.
 */
public class ExternalStore<I, P>
	{
	public final Class<I> type;
	private final WeakHashMap<I, P> store;
	private final ObjectSpawner<P> spawner;
	
	/**
	 * Create a new store for the given field type on the given object type. Only one store should be created per field per object class.
	 * @param objectType The type of the object to which we want to assign a field. The class reference is kept to ensure type safety.
	 * @param defaultValue A spawner which generates mutable objects of the field type. One field instance is created for each object instance.
	 */
	public ExternalStore(Class<I> objectType, ObjectSpawner<P> defaultValue)
		{
		this.type = objectType;
		this.spawner = defaultValue;
		this.store = new WeakHashMap<>();
		}
	/**
	 * Get the value of the field represented by this store, for the given object instance.
	 * @param instance The object instance.
	 * @return The field value. On the first call to this method for some instance, the default value from the object spawner is returned.
	 */
	public P get(I instance)
		{
		if(!(type.isAssignableFrom(instance.getClass())))
			return null;
		P p = store.get(instance);
		if(p == null)
			{
			p = spawner.createInstance();
			store.put((I) instance, p);
			}
		return p;
		}
	}
